package io.kiki.sba.registry.server.metadata.slot.util.comparator;

import io.kiki.sba.registry.common.model.slot.DataStoreNode;
import io.kiki.sba.registry.server.metadata.slot.util.builder.SlotsBuilder;

import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;


public class Comparators {

    public static DataStoreNodeFollowerSizeComparator mostFollowersFirst(SlotsBuilder slotsBuilder) {
        return new DataStoreNodeFollowerSizeComparator(slotsBuilder, SortType.des);
    }

    public static DataStoreNodeFollowerSizeComparator leastFollowersFirst(SlotsBuilder slotsBuilder) {
        return new DataStoreNodeFollowerSizeComparator(slotsBuilder, SortType.asc);
    }

    public static DataStoreNodeLeaderSizeComparator mostLeadersFirst(SlotsBuilder slotsBuilder) {
        return new DataStoreNodeLeaderSizeComparator(slotsBuilder, SortType.des);
    }

    public static DataStoreNodeLeaderSizeComparator leastLeadersFirst(SlotsBuilder slotsBuilder) {
        return new DataStoreNodeLeaderSizeComparator(slotsBuilder, SortType.asc);
    }

    public abstract static class AbstractSlotComparator<T> implements Comparator<T> {

        protected SlotsBuilder slotsBuilder;

        protected SortType sortType;

        public AbstractSlotComparator(SlotsBuilder slotsBuilder, SortType sortType) {
            this.slotsBuilder = slotsBuilder;
            this.sortType = sortType;
        }
    }

    /**
     * ---------------------------------- Data Server Comparators
     * --------------------------------------------
     */
    public abstract static class AbstractDataStoreNodeComparator extends AbstractSlotComparator<String> {

        public AbstractDataStoreNodeComparator(SlotsBuilder slotsBuilder, SortType sortType) {
            super(slotsBuilder, sortType);
        }

        @Override
        public int compare(String dataServer1, String dataServer2) {
            DataStoreNode dataStoreNode1 = slotsBuilder.getDataStoreNode(dataServer1);
            DataStoreNode dataStoreNode2 = slotsBuilder.getDataStoreNode(dataServer2);
            int score = getFirstClassMember(dataStoreNode1).size() - getFirstClassMember(dataStoreNode2).size();
            if (score == 0) {
                score = getEconomyMember(dataStoreNode1).size() - getEconomyMember(dataStoreNode2).size();
            }
            return sortType.getScore(score);
        }

        protected Collection<Integer> getFirstClassMember(DataStoreNode dataStoreNode) {
            return Collections.emptyList();
        }

        protected Collection<Integer> getEconomyMember(DataStoreNode dataStoreNode) {
            return Collections.emptyList();
        }

        ;
    }

    public static class DataStoreNodeFollowerSizeComparator extends AbstractDataStoreNodeComparator {

        public DataStoreNodeFollowerSizeComparator(SlotsBuilder slotsBuilder, SortType sortType) {
            super(slotsBuilder, sortType);
        }

        @Override
        protected Collection<Integer> getFirstClassMember(DataStoreNode dataStoreNode) {
            return dataStoreNode.getFollowerSlotIdSet();
        }

        @Override
        protected Collection<Integer> getEconomyMember(DataStoreNode dataStoreNode) {
            return dataStoreNode.getLeaderSlotIdSet();
        }
    }

    public static class DataStoreNodeLeaderSizeComparator extends AbstractDataStoreNodeComparator {

        public DataStoreNodeLeaderSizeComparator(SlotsBuilder slotsBuilder, SortType sortType) {
            super(slotsBuilder, sortType);
        }

        @Override
        protected Collection<Integer> getFirstClassMember(DataStoreNode dataStoreNode) {
            return dataStoreNode.getLeaderSlotIdSet();
        }

        @Override
        protected Collection<Integer> getEconomyMember(DataStoreNode dataStoreNode) {
            return dataStoreNode.getFollowerSlotIdSet();
        }
    }

}
